﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using Windows.UI.Notifications;
using TileNotificationsPack.Attributes;
using Windows.Data.Xml.Dom;

namespace TileNotificationsPack
{
   public static class TileUpdaterExtensions
   {
      public static void Update(this TileUpdater updater, Tile tile)
      {
         if (updater == null)
            throw new ArgumentNullException("updater");

         if (tile == null)
            throw new ArgumentNullException("tile");

         updater.Update(new TileNotification(CreateTileXml(tile)));
      }

      public static void Update(this TileUpdater updater, IEnumerable<Tile> tiles)
      {
         if (updater == null)
            throw new ArgumentNullException("updater");

         if (tiles == null)
            throw new ArgumentNullException("tiles");

         XmlDocument xmldoc = null;

         foreach(var tile in tiles)
         {
            var tilexml = CreateTileXml(tile);

            if (xmldoc == null)
            {
               xmldoc = tilexml;
            }
            else
            {
               var tileBindingNode = tilexml.GetElementsByTagName("binding").FirstOrDefault();
               if(tileBindingNode != null)
               {
                  var docBindingNode = xmldoc.ImportNode(tileBindingNode, true);
                  var visual = xmldoc.GetElementsByTagName("visual").FirstOrDefault();

                  if(visual != null)
                     visual.AppendChild(docBindingNode);
               }
            }
         }

         updater.Update(new TileNotification(xmldoc));
      }

      private static XmlDocument CreateTileXml(Tile tile)
      {
         var type = tile.GetType();
         var typeinfo = type.GetTypeInfo();
         var attrs = typeinfo.GetCustomAttributes<TileTemplateAttribute>(true).ToList();
         if (attrs.Count == 0)
            throw new TileNotificationsException("Invalid tile object.");

         var ttattr = attrs[0] as TileTemplateAttribute;

         var xmldoc = TileUpdateManager.GetTemplateContent(ttattr.Template);

         var properties = type.GetRuntimeProperties().ToList();
         foreach (var property in properties)
         {
            var proptypeinfot = property.GetCustomAttributes<TextNodeAttribute>(true).ToList();

            if (proptypeinfot.Count > 0)
            {
               var tattr = proptypeinfot[0] as TextNodeAttribute;
               if (tattr != null)
               {
                  var nodes = xmldoc.GetElementsByTagName(tattr.Node);
                  var node = nodes.Item((uint)(tattr.Id - 1));
                  if (node != null)
                  {
                     node.InnerText = property.GetValue(tile) as string;
                  }
               }
            }

            var proptypeinfoi = property.GetCustomAttributes<ImageNodeAttribute>(true).ToList();

            if (proptypeinfoi.Count > 0)
            {
               var iattr = proptypeinfoi[0] as ImageNodeAttribute;
               if (iattr != null)
               {
                  var nodes = xmldoc.GetElementsByTagName(iattr.Node);
                  var node = nodes.Item((uint)(iattr.Id - 1));
                  if (node != null)
                  {
                     var image = property.GetValue(tile) as TileImage;
                     if (image != null)
                     {
                        var src = xmldoc.CreateAttribute("src");
                        src.Value = image.Src;
                        node.Attributes.SetNamedItem(src);

                        var alt = xmldoc.CreateAttribute("alt");
                        alt.Value = image.Alt;
                        node.Attributes.SetNamedItem(alt);
                     }
                  }
               }
            }
         }

         if(tile.Binding != null)
         {
            var tileBindingNode = xmldoc.GetElementsByTagName("binding").FirstOrDefault();
            if (tileBindingNode != null)
            {
               if(!string.IsNullOrEmpty(tile.Binding.Language))
               {
                  var battr = xmldoc.CreateAttribute("lang");
                  battr.Value = tile.Binding.Language;
                  tileBindingNode.Attributes.SetNamedItem(battr);
               }
               if (!string.IsNullOrEmpty(tile.Binding.BaseUri))
               {
                  var battr = xmldoc.CreateAttribute("baseUri");
                  battr.Value = tile.Binding.BaseUri;
                  tileBindingNode.Attributes.SetNamedItem(battr);
               }
               if (!string.IsNullOrEmpty(tile.Binding.ContentId))
               {
                  var battr = xmldoc.CreateAttribute("contentId");
                  battr.Value = tile.Binding.ContentId;
                  tileBindingNode.Attributes.SetNamedItem(battr);
               }
               if (tile.Binding.ImageQuery.HasValue)
               {
                  var battr = xmldoc.CreateAttribute("addImageQuery");
                  battr.Value = tile.Binding.ImageQuery.Value.ToString();
                  tileBindingNode.Attributes.SetNamedItem(battr);
               }
               if (tile.Binding.Branding.HasValue)
               {
                  var battr = xmldoc.CreateAttribute("branding");
                  battr.Value = tile.Binding.Branding.Value.ToString();
                  tileBindingNode.Attributes.SetNamedItem(battr);
               }
            }
         }

         return xmldoc;
      }
   }
}
